package com.ruoyi.common.datasource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Spring Boot 适配的 MySQL 脚本执行组件
 */
@Component
public class MysqlScriptExecutor {

    private final JdbcTemplate jdbcTemplate;
    private final DataSourceProperties dataSourceProperties;

    @Autowired
    public MysqlScriptExecutor(JdbcTemplate jdbcTemplate, DataSourceProperties dataSourceProperties) {
        this.jdbcTemplate = jdbcTemplate;
        this.dataSourceProperties = dataSourceProperties;
    }

    /**
     * 执行类路径下的 SQL 脚本
     * @param scriptPath 类路径下的脚本路径（如 "scripts/init.sql"）
     * @return 执行结果
     * @throws IOException 脚本读取异常
     * @throws SQLException SQL 执行异常
     */
    public ExecutionResult executeClassPathScript(String scriptPath) throws IOException, SQLException {
        File file = new File(scriptPath);
        if (!file.exists()) {
            throw new IOException("Script file not found: " + scriptPath);
        }
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8))) {
            List<String> sqlStatements = parseScript(reader);
            return executeSqlStatements(sqlStatements);
        }
    }

    /**
     * 执行 SQL 语句列表
     * @param sqlStatements SQL 语句列表
     * @return 执行结果
     * @throws SQLException SQL 执行异常
     */
    private ExecutionResult executeSqlStatements(List<String> sqlStatements) throws SQLException {
        ExecutionResult result = new ExecutionResult();
        for (String sql : sqlStatements) {
            String trimmedSql = sql.trim();
            if (trimmedSql.isEmpty()) continue;

            result.incrementTotal();
            try {
                jdbcTemplate.execute(trimmedSql);
                result.incrementSuccess();
            } catch (Exception e) {
                result.addFailedSql(trimmedSql);
                result.addError(e.getMessage());
            }
        }
        return result;
    }

    /**
     * 解析 SQL 脚本为语句列表
     * @param reader 脚本读取流
     * @return SQL 语句列表
     * @throws IOException 读取异常
     */
    private List<String> parseScript(BufferedReader reader) throws IOException {
        List<String> statements = new ArrayList<>();
        StringBuilder currentStatement = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            String trimmedLine = line.trim();
            // 跳过注释和空行
            if (trimmedLine.startsWith("--") || trimmedLine.isEmpty()) {
                continue;
            }

            currentStatement.append(line).append("\n");
            // 以分号结尾的语句为完整语句
            if (trimmedLine.endsWith(";")) {
                String statement = currentStatement.toString()
                        .substring(0, currentStatement.length() - 1) // 移除分号
                        .trim();
                statements.add(statement);
                currentStatement.setLength(0);
            }
        }
        // 处理最后一条未以分号结尾的语句
        if (currentStatement.length() > 0) {
            statements.add(currentStatement.toString().trim());
        }
        return statements;
    }

    /**
     * 执行结果封装类
     *
     * 成功：total 执行总数 === success 成功数  才算是成功
     */
    public static class ExecutionResult {
        private int total;
        private int success;
        private final List<String> failedSqls = new ArrayList<>();
        private final List<String> errors = new ArrayList<>();

        public int getTotal() { return total; }
        public int getSuccess() { return success; }
        public List<String> getFailedSqls() { return failedSqls; }
        public List<String> getErrors() { return errors; }

        public void incrementTotal() { this.total++; }
        public void incrementSuccess() { this.success++; }
        public void addFailedSql(String sql) { this.failedSqls.add(sql); }
        public void addError(String error) { this.errors.add(error); }
    }

}